﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using IntoNails.Infrastructure.DataAccess;
using IntoNails.Infrastructure.Extensions;
using IntoNails.Models;

namespace IntoNails.DataAccess
{
    [Serializable]
    public class UserRepository : AbstractDataRepository<User, Guid>, IDataFileRepository, IUserRepository
    {
        public UserRepository(string dataFilePath)
        {
            this.DataFilePath = dataFilePath;
        }

        #region Implementation of IDataFileRepository

        public string DataFilePath { get; set; }

        #endregion
        
        #region Overridens

        public override User Get(Guid uniqueCode)
        {
            return this.InnerDataList.SingleOrDefault(u => u.UniqueCode == uniqueCode);
        }

        public override IEnumerable<User> Get(Func<User, bool> predicate)
        {
            return this.InnerDataList.Where(predicate);
        } 

        public override IList<User> GetRawItemList()
        {
            return this.InnerDataList;
        }

        public override void Add(User item)
        {
            if (null == item)
            {
                this.OnDataAdded(new DataEventArgs<User>(new ArgumentNullException("item")));
            }
            else if (this.InnerDataList.Contains(item))
            {
                this.OnDataAdded(new DataEventArgs<User>(false));
            }
            else
            {
                this.InnerDataList.Add(item);
                this.OnDataAdded(new DataEventArgs<User>(true));
            }
        }

        public override void Remove(Guid uniqueCode)
        {
            User removedUser = this.Get(uniqueCode);
            if (null == removedUser)
            {
                this.OnDataRemoved(new DataEventArgs<User>(new ArgumentNullException("removedUser")));
            }
            else
            {
                this.InnerDataList.Remove(removedUser);
                this.OnDataRemoved(new DataEventArgs<User>(true));
            }
        }

        public override void Update(Guid oldItemKey, User newItem)
        {
            User oldUser = this.Get(oldItemKey);
            if (null == oldUser)
            {
                this.Add(newItem);
            }
            else if (null == newItem)
            {
                this.OnDataUpdated(new DataUpdatedEventArgs<User>(new ArgumentNullException("newItem")));
            }
            else
            {
                oldUser = newItem;
                ////oldUser.FirstName = newItem.FirstName;
                ////oldUser.MiddleName = newItem.MiddleName;
                ////oldUser.LastName = newItem.LastName;
                ////oldUser.Username = newItem.Username;
                ////oldUser.Password = newItem.Password;
                ////oldUser.IsValid = newItem.IsValid;

                this.OnDataUpdated(new DataUpdatedEventArgs<User>(true));
            }
        }

        public override void Save()
        {
            using (Stream saveDataStream = new FileStream(this.DataFilePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                this.InnerDataList.Serialize(saveDataStream);
            }
        }

        public override int Load()
        {
            if (!File.Exists(this.DataFilePath))
            {
                this.InnerDataList = new List<User>();
            }
            else
            {
                using (Stream loadDataStream = new FileStream(this.DataFilePath, FileMode.Open, FileAccess.Read))
                {
                    this.InnerDataList = loadDataStream.Deserialize<List<User>>();
                }
            }

            return this.InnerDataList.Count;
        }

        public override void Initialize()
        {
            base.InnerDataList = new List<User>();
        }

        #endregion

        #region Methods
        
        #endregion

        #region Implementation of IUserRepository

        public User Login(string username, string password)
        {
            return this.InnerDataList.SingleOrDefault(user => user.Username == username && user.Password == password);
        }

        public User Register()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
